$ arr[0]="ABC"
$ arr[1]="DEF"
$ arr[2]="GHI"
$ echo "${arr[1]}"
DEF
$ echo ${#arr[@]}
3
参考
arr[0]="ABC"
… 配列に格納します。
"${arr[1]}"
… 配列の要素を返します。
${#arr[@]}
… 配列の要素数を返します。
arr=( "ABC" \
"DEF" "GHI" )
for (( i = 0; i < ${#arr[@]}; i ++ ));do
echo "${arr[$i]}"
done
arr
arr
関連
空白で区切られたそれぞれの値でループ
arr=( "ABC" "DEF" "GHI" )
for elem in "${arr[@]}" ;do
echo "$elem"
done
elem
elem
arr
arr
for 要素 in 配列 方式:
配列番号方式:
関連
for a in "${arr[@]}";do echo $a ;done
… 配列の要素を一覧します。(改行あり)
arr
arr=("${arr[@]}" "add")
… 配列の末尾の要素の次に追加します。
break が使えますが、
break でループを抜けたか、
最後の要素までループしたかを
elem の値から判定することはできません。
echo "${arr[@]}"
… 配列の要素を一覧します。(フィールド形式。改行なし)
arr
… 配列をコピーします。
arr2=("${arr[@]}")
${!arr[@]}
… 配列の番号を一覧します。(フィールド形式)
$ fields="ABC DEF GHI"
$ echo $fields | cut -d" " -f2
DEF
$ echo $fields | cut -d" " -f1-3
ABC DEF GHI
$ echo $fields | cut -d" " -f1,3
ABC GHI
$ echo ${#arr}
11
fields="ABC DEF GHI"
for elem in $fields ;do
echo $elem
done
参考
${#fields}
… 文字数
… cut コマンドは、区切り文字を指定して要素を参照
…
"$fields" ではなく $fields にしてください。
" " で囲まないときは、値に含まれる空白文字や改行文字を
フィールドに分割します。
ちなみに、配列のときは "${arr[@]}" のように " " で囲まなければ、
配列要素の中の空白文字を要素の区切りと判定してしまいます。
declare -A ObjectA #// associative array
ObjectA["Attr1"]="Value1"
ObjectA[Attr2]="Value2"
ObjectA["Attr3"]="Value3"
echo ${ObjectA["Attr1"]} #// "Value1"
echo ${ObjectA["Attr2"]} #// "Value2"
echo ${ObjectA[Attr3]} #// "Value3"
attr_name="Attr2"
echo ${ObjectA[$attr_name]} #// "Value2"
declare -A ObjectA #// associative array
ObjectA=( [Attr1]="Value1" [Attr2]="Value2" )
echo ${ObjectA[Attr1]} #// "Value1"
echo ${ObjectA["Attr2"]} #// "Value2"
[ ] の中は文字列ですが、
" " で囲む必要はありません。
連想配列の基本
連想配列の初期化子
参考
連想配列の集合処理
declare -A ObjectA #// associative array
ObjectA["Attr1"]="Value1"
ObjectA["Attr2"]="Value2"
echo ${!ObjectA[@]} #// Attr1 Attr2
echo ${ObjectA[@]} #// Value1 Value2
関数の中からグローバル変数として declare するには、-g オプションを指定します。
ただし、bash 4.2 から使えます。
その他
変数の型
#// global variables as associative arrray
declare -A g_ObjectA
declare -A g_ObjectB
function InitObjs_func()
{
g_ObjectA["Attr1"]="Value1" #// g_ObjectA.Attr1 = "Value1"
g_ObjectA["Attr2"]="Value2"
g_ObjectB["Attr1"]="$( Attr_func g_ObjectA "Value1" )"
g_ObjectB["Attr2"]="Value4"
}
function Attr_func()
{
local self_name="$1" #// または local self ; CopyArray_func self "$1"
local AttrName="$2"
eval echo "\${${self_name}[\$AttrName]}" #// または echo "${self[$AttrName]}"
}
InitObjs_func
for obj in ${g_Objects[@]};do
echo "`Attr_func $obj "Attr2" `" #// echo g_ObjectA.Attr2
done
関連
declare -A が無くても、ObjectA["Attr1"] を実行すると連想配列が作られます。
declare を関数内で実行するとローカル、関数の外で実行するとグローバルになります。
関数の引数には指定できません。 オブジェクトはグローバルにせざるを得ないでしょう。
bash ver3 のための擬似連想配列
g_ObjectA["Attr1"]="Value1"
bash ver4 で使える連想配列
bash ver3 でも使える bashlib 関数
SetAttr_func g_ObjectA "Attr1" "Value1"
SetAttr_func の実装
eval "$self[$AttrName]=\"$Value\""
属性(メンバー変数)
メソッド(メンバー関数)
関連
#!/bin/bash -eE
export g_Objects=( "g_ObjectA" "g_ObjectB" )
for obj in ${g_Objects[@]};do declare -A $obj ; done
#// associative array
function InitObjs_func()
{
g_ObjectA["Class"]="AClass"
g_ObjectA["Attr1"]="ValueA"
g_ObjectA["doA_method"]="AClass.doA_method"
g_ObjectB["Class"]="BClass"
g_ObjectB["Attr1"]="ValueB"
g_ObjectB["doA_method"]="BClass.doA_method"
}
function Main_func()
{
local obj
InitObjs_func
for obj in ${g_Objects[@]};do
$( Attr_func $obj "doA_method" ) $obj
done
}
function AClass.doA_method()
{
local self="$1"
echo "AClass.doA_method( $self )"
}
function BClass.doA_method()
{
local self="$1"
echo "BClass.doA_method( $self )"
}
function Attr_func()
{
local self="$1"
local AttrName="$2"
eval echo "\${${self}[\$AttrName]}"
}
Main_func
g_SetupFileNames=( "./Child1.sh" "./Child2.sh" )
function Main_func()
{
local name_sh ; local result
for name_sh in ${g_SetupFileNames[@]};do
$name_sh --FuncA_func --Param1=Value1 --Param2=Value2
done
for name_sh in ${g_SetupFileNames[@]};do
result=`$name_sh --FuncB_func --Param1=Value1`
echo "\$result = $result"
done
}
Main.sh
g_AllArguments="$@"
g_FuncName=${1#--*} #// cut -- from $1
function Main_func()
{
$g_FuncName $g_AllArguments
}
function FuncA_func()
{
echo "FuncA_func in Package1.sh"
}
function FuncB_func()
{
echo "FuncB_func in Package1.sh"
}
Child1.sh
g_AllArguments="$@"
g_FuncName=${1#--*} #// cut -- from $1
function Main_func()
{
$g_FuncName $g_AllArguments
}
function FuncA_func()
{
echo "FuncA_func in Package1.sh"
}
function FuncB_func()
{
echo "FuncB_func in Package1.sh"
}
Child2.sh
関連
関数名は、クラス名+Class+ピリオド+メソッド名_method。
クラス名は、単語の先頭は大文字、後は小文字。(Java準拠)
メソッド名は、先頭の単語はすべて小文字、後の単語は先頭文字のみ大文字。(Java準拠)
メソッドに相当する関数の第1引数は、オブジェクトの名前(=連想配列の
名前)。 関数内では、self という変数名にする。
function SampleClass.doSample_method()
{
local self="$1"
サンプル
オブジェクトの名前を、ファイル名、または、第1パラメーターにします。
メソッド名を、関数名と同じ、パラメーターなしのオプションにします。
メソッドのパラメーターを、パラメーターありのオプションにします。
#!/bin/bash -x
#// -x option echos commands
set -e #// -e option does not continue, if error was raised
cp NoFile NoFolder
echo Error ignored
set +e #// +e option does not exit shell, if error was raised
set -e を実行すると、エラーが発生したときに続きを実行しないようになります。
エラーが発生したと判定するときは、実行したコマンドの終了コードが 0 以外のときです。
set +e で、set -e を無効にしているのは、シェルから入力したコマンドでエラーが
発生しても、シェルが終了してしまうのを避けるためです。
if [ ! -e NoFile ]; then unset ERROR;${ERROR:?not found NoFile};fi
m-toda@nk4lx5:~$ unset ERROR;${ERROR:?This is error test}
-bash: ERROR: This is error test
unset ERROR;${ERROR:?Error message}
変数が定義されていなければエラーにする構文 ${VAR:?message} を応用して、
エラーを発生させる方法です。
サンプル
サンプル
ファイルがないときにエラーにする
#!/bin/bash -eE
#// -eE option does not continue, if error was raised
echo success && echo AND
echo success || echo OR
cp NoFile NoFolder && echo AND
cp NoFile NoFolder || echo OR
cp NoFile NoFolder || cp NoFile NoFolder
echo Error ignored
&& は、&& の左のコマンドの終了コードが 0 (正常)だったときに、&& の右のコマンドを実行します。
|| は、|| の左のコマンドの終了コードが 0 以外(エラー)だったときに、|| の右のコマンドを実行します。
&& または || の左のコマンドがエラーになっても、set -e によって、スクリプトが中断されることは
ありません。 && または || の左のコマンドがエラーになったら中断します。
#!/bin/bash -xe
#// -x option echos commands
#// -e option does not continue, if error was raised
cp NoFile NoFolder
echo Error ignored
-xe は、-x オプションと -e オプションの両方を指定するという意味です。
上下のシェルスクリプトは、同じ内容です。
echo success && echo AND ; echo after
echo success || echo OR ; echo after
; の後は、&& || の影響を受けないで、必ず実行します。
これは非推奨です。
推奨
これは非推奨です。
推奨
(ただし、終了コードは 0 になってしまいます。)
参考
関数呼び出しの後に && または || を記述すると、関数内でエラーが発生しても、すぐに
返らないで、続きを実行してしまいます。
これは非推奨です。
推奨
非推奨
推奨
関連
0 EXIT exit the program, not actual signal
1 HUP hang up, will actually cause a daemon to reread the configuration file
2 INT Interrupt or stop running, you can do this with Ctrl+C
3 QUIT quit key, CTRL+SHIFT or CTRL+SHFT+\
9 KILL stop immediately regardless of anything else, this is like an emergency kill switch
15 TERM terminate nicely if at all possible
18 CONT continue execution, this will start a stopped process
20 TSTP stop executing, continue
DEBUG execute commands specified in trap statement
ERR execute commands specified in trap statement after each command
trap 'echo trapped' EXIT
#!/bin/bash -xe
#// -x option echos commands
#// -e option does not continue, if error was raised
cp NoFile NoFolder
echo Error ignored
先頭の #!/bin/bash に -x を付けると、実行しているコマンドを表示しながら実行します。
-v をつけた場合、関数の中に入ると表示しなくなります。
user1@linux:~$ ~/temporary.sh
+ cp NoFile NoFolder
cp: `NoFile' を stat できません: そのようなファイルやディレクトリはありません
temporary.sh
シェルの表示内容
function err_trap {
echo ""
if [ "${#FUNCNAME[@]}" == "2" ]; then
echo "(Hint) Line number is shown by following trap command in the top of script."
echo " " trap \'echo "\$BASH_SOURCE\\(\$LINENO\\)"\' DEBUG
else
for(( i=1; i < ${#FUNCNAME[@]}; i++ ));do
echo "callstack[$i]=${FUNCNAME[$i]} ${BASH_SOURCE[$i-1]}(${BASH_LINENO[$i-1]})"
done
echo "(Hint) Line number in ${FUNCNAME[1]} function is shown by following trap command in the top of ${FUNCNAME[1]} function."
echo " " trap \'echo "\$BASH_SOURCE\\(\$LINENO\\) in \$FUNCNAME\\(\\)"\' DEBUG
fi
}
trap 'set +x ; err_trap' EXIT
main_func
trap '' EXIT
次のようにすると、main_func の中でエラーが発生すると、コールスタックを表示します。
関数の外の場合
関数の中の場合
先頭行のオプションについては、
で "set [" を検索してください。
trap 'echo "$LINENO: $BASH_COMMAND"' DEBUG
-x が無くても、下記を記述すると、コマンドラインを表示しながら実行します。行番号付き。
ただし、関数の中に入ると、表示しなくなります。
trap 'read -p "$LINENO: $BASH_COMMAND" key' DEBUG
下記を記述すると、ステップ実行します。 Enter キーを押すと、1行進みます。
ステップ・インはできません。 ステップ・オーバーだけです。
./sample.sh: 行 369: 予期しないトークン `}' 周辺に構文エラー があります
} が関数の終了のときは、その関数の中で、if 〜 fi や case 〜 esac の対応関係が合っていません。
参考
→ BashSyntax (vbslib)
#!/bin/bash -eE
function Main_func()
{
local var1=$( NotDefined_func "a" )
echo "<ERROR msg=\"Do not come here 1\"/>"
local var=`NotDefined "a"`
echo "<ERROR msg=\"Do not come here 2\"/>"
local var; var=$( NotDefined_func "a" )
echo "<ERROR msg=\"Do not come here 3\"/>"
}
Main_func
$ ./temp.sh
./temp.sh: line 5: NotDefined_func: コマンドが見つかりません
<ERROR msg="Do not come here 1"/>
./temp.sh: line 8: NotDefined_func: コマンドが見つかりません
<ERROR msg="Do not come here 2"/>
./temp.sh: line 11: NotDefined_func: コマンドが見つかりません
temp.sh
呼び出すコマンドや関数が見つからないとき、関数の返り値を local コマンドと同時に
使用すると、続きを実行してしまいます。(下記var1への代入)
local コマンドと同時でなければ、正しく実行を中断します。(下記var2への代入)
実行結果
g_Var="1"
function Caller_func()
{
local tmp
tmp=`Called_func` #// echo 出力を格納
echo "$tmp" #// "output"
echo "$g_Var" #// "1" のまま
}
function Called_func()
{
g_Var="a" #// echo 出力が取得されるとき、グローバルの変更は無効
echo "output"
}
呼び出した関数の echo 出力を取得するとき、呼び出した関数の中でグローバル
変数の値を変更しても、リターンするときに元に戻ります。
(cache)